﻿using System.Linq;
using Daemon.Common;
using Daemon.Common.Helpers;
using Daemon.Infrustructure.EF;
using Daemon.Repository.EF.Enums;
using Daemon.Repository.Contract;
using Daemon.Model;
using System;
using System.Linq.Expressions;
using System.Collections.Generic;

namespace Daemon.Repository.EF
{
	public class TakeAwayRuleDetailRepository : Repository<TakeAwayRuleDetail>, ITakeAwayRuleDetailRepository
	{
		private readonly ITakeAwayRuleDetailValueRepository _takeAwayRuleDetailValueRepository;

		protected override Expression<Func<TakeAwayRuleDetail, int>> PrimaryKeyExpression => r => r.Id;

		public TakeAwayRuleDetailRepository(ApiDBContent context, ITakeAwayRuleDetailValueRepository takeAwayRuleDetailValueRepository) : base(context)
		{
			_takeAwayRuleDetailValueRepository = takeAwayRuleDetailValueRepository;
		}

		protected override void UpdateEntitiesBeforeCreate(IEnumerable<TakeAwayRuleDetail> entities, ApiDBContent context)
		{
			AddRuleDetailValues(entities);

			base.UpdateEntitiesBeforeCreate(entities, context);
		}

		protected override void UpdateEntitiesBeforeUpdate(IEnumerable<TakeAwayRuleDetail> entities, ApiDBContent context)
		{
			AddRuleDetailValues(entities);

			base.UpdateEntitiesBeforeUpdate(entities, context);
		}

		protected override void UpdateEntitiesAfterCreate(IEnumerable<TakeAwayRuleDetail> entities, ApiDBContent context)
		{
			base.UpdateEntitiesAfterCreate(entities, context);
		}

		protected override void UpdateEntitiesAfterUpdate(IEnumerable<TakeAwayRuleDetail> entities, ApiDBContent context)
		{
			base.UpdateEntitiesAfterUpdate(entities, context);
		}

		protected override void SaveRelationships(TakeAwayRuleDetail entity, TakeAwayRuleDetail entityWithRelationships, ApiDBContent db, short entityORMType)
		{
			AddPriceProperties(entity, entityWithRelationships);

			base.SaveRelationships(entity, entityWithRelationships, db, entityORMType);
		}

		protected override IEnumerable<TakeAwayRuleDetail> IncludeRelationships(IEnumerable<TakeAwayRuleDetail> entities, ApiDBContent db)
		{
			SetGoodRuleInfo(entities);

			SetRuleDetailValue(entities);

			return base.IncludeRelationships(entities, db);
		}

		private void AddPriceProperties(TakeAwayRuleDetail entity, TakeAwayRuleDetail entityWithRelationships)
		{
			if (!RouteParameterHelper.CheckRouteParameter(RelationshipNames, TakeAwayRuleDetailRelationShipEnum.AddPriceProeperty))
			{
				return;
			}

			var goodIds = entityWithRelationships.AddPriceProperty.Select(r => r.GoodId).ToList();
			entityWithRelationships.AddPriceProperty.ForEach(r =>
			{
				r.RuleDetailId = entity.Id;
			});

			_takeAwayRuleDetailValueRepository.DeleteRange(Context.TakeAwayRuleDetailValue.Where(r => goodIds.Contains(r.GoodId)));
			_takeAwayRuleDetailValueRepository.AddRangeByDBContext(entityWithRelationships.AddPriceProperty);
		}

		private void AddRuleDetailValues(IEnumerable<TakeAwayRuleDetail> entities)
		{
			if (!RouteParameterHelper.CheckRouteParameter(RelationshipNames, TakeAwayRuleDetailRelationShipEnum.DetailValue))
			{
				return;
			}

			var ids = entities.Select(r => r.Id).ToList();
			List<TakeAwayRuleDetailValue> listValues = new List<TakeAwayRuleDetailValue>();
			foreach (var entity in entities)
			{
				var values = entity.Detail.Split(',');
				listValues.AddRange(values.Select(r => new TakeAwayRuleDetailValue()
				{
					Value = r,
					RuleDetailId = entity.Id,
					IsDefault = entity.DefaultValue == r
				}));
			}

			_takeAwayRuleDetailValueRepository.DeleteRange(Context.TakeAwayRuleDetailValue.Where(r => ids.Contains(r.RuleDetailId)));
			_takeAwayRuleDetailValueRepository.AddRangeByDBContext(listValues);
		}

		private void SetRuleDetailValue(IEnumerable<TakeAwayRuleDetail> entities)
		{
			if (!RouteParameterHelper.CheckRouteParameter(RelationshipNames, TakeAwayRuleDetailRelationShipEnum.DetailValue))
			{
				return;
			}

			var detailIds = entities.Select(r => r.Id).ToList();
			var dicDetailValue = Context.TakeAwayRuleDetailValue.Where(r => detailIds.Contains(r.RuleDetailId)).ToList().GroupBy(r => r.RuleDetailId).ToDictionary(r => r.Key, r => r.ToList());
			foreach (var entity in entities)
			{
				if (dicDetailValue.TryGetValue(entity.Id, out List<TakeAwayRuleDetailValue> values))
				{
					entity.Values = values;
				}
			}
		}

		private void SetGoodRuleInfo(IEnumerable<TakeAwayRuleDetail> entities)
		{
			if (!RouteParameterHelper.CheckRouteParameter(RelationshipNames, TakeAwayRuleDetailRelationShipEnum.RuleInfo))
			{
				return;
			}

			var ruleIds = entities.Select(r => r.RuleId).ToList();
			var dicGoodRule = Context.TakeAwayGoodRule.Where(r => ruleIds.Contains(r.Id)).ToDictionary(r => r.Id, r => r);
			foreach (var entity in entities)
			{
				if (dicGoodRule.TryGetValue(entity.RuleId, out TakeAwayGoodRule rule))
				{
					entity.RuleName = rule.Name;
				}
			}
		}
	}
}
